package priv.conceit.study.book.thread.chapter2.parts5;

/**
 * 2.5.2
 * java 内存模型(jvm内存结构)
 * <p>
 * 此章高能 大多为jvm底层
 * <p>
 * java在执行java 程序时会把对应的物理内存划分为不同的内存区域
 * 每一个内存区域存放着不同的内存区域,也用不同的创建与销毁时机
 * 有些分区在jvm启动的时候就创建，有些则是在运行的时候才创建,比如虚拟机栈
 * “堆内存、栈内存”中的“栈内存”指的便是虚拟机栈，确切地说，指的是虚拟机栈的栈帧中的局部变量表
 * <p>
 * jdk1.8 之前的内存模型图
 * <a herf="https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=644020471,1780302824&fm=173&app=25&f=JPEG?w=640&h=397&s=8DC6ED17095D70C85A5CA4F403004031"></a>
 * <p>
 * jdk1.8 之后
 * 持久代内存被彻底删除,取而代之的是metaSpace 元空间
 * 元空间同样是堆内存的一部分 jvm为每个类加载器分配一块内存块列表，进行线性分配，块的大小取决于类加载器的类型
 * sun/反射/代理对应的类加载器会小一些，之前的版本会单独卸载回收某个类
 * 而现在是在cg的过程中发现某个类加载器已经具备回收的条件，则会将整个类加载器的相关的元空间全部收回，从而减少gc扫描和压缩的时间
 *
 * @author Conceit
 * @since 1.0.0, 2019/6/10
 */
public class JavaMemoryModel {

	/**
	 * 程序计数器
	 * 1-线程私有
	 * 2-执行native本地方法时，程序计数器的值为空（Undefined）
	 * 3-执行java方法时，程序计数器是有值的，且记录的是正在执行的字节码指令的地址
	 * 4-程序计数器占用内存很小，在进行JVM内存计算时，可以忽略不计
	 * 5-程序计数器，是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError的区域
	 * <p>
	 * 无论任何语言，都要通过操作系统的控制总线向cpu发出机器指令，java也一样
	 * 程序计数器在java中所起到的作用
	 * 存放当前线程接下来要执行的字节码，分支，循环，异常信息，跳转等信息
	 * cpu在任何时间只能处理一个线程的指令，为了使cpu能在时间片轮转切换上下文之后能够正常的回到正常的执行位置
	 * 每个线程都需要具有一个独立的程序计数器，各个线程之间互相不影响，所以此块内存区域为线程私有
	 */
	private void programCounterRegister() {
	}

	/**
	 * jvm栈-文章里重点介绍
	 * <p>
	 * <p>
	 * 1-线程私有
	 * 2-生命周期与线程相同
	 * 3-jvm运行时创建
	 * 4-可通过-xssl来配置大小
	 * 5-方法在执行中会创建一个名为 栈帧 的数据结构stack frame 主要存放局部变量表，操作栈，动态链接，方法出口
	 * 6-每个方法的调用对应着栈帧中的在jvm栈中的压栈和弹栈过程
	 * 7-每个线程会有多个方法 所以每个线程的虚拟机栈中 对应多个栈帧
	 * 8-同等的虚拟机栈如果 栈帧中局部变量表等占用的内存越小，则可以压入的栈帧就越多，反之亦然
	 * 9-一般将栈帧内存的大小称为宽度，数量称为深度
	 * 10-缩略图<a href="https://img-blog.csdn.net/20170816135728274?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvWUNoZW5GZW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/">
	 */
	private void jvmStack() {
	}

	/**
	 * java 本地方法栈
	 * java native interface stack
	 * <p>
	 * 1-线程私有
	 * 2-生命周期与线程相同
	 * 3-java虚拟机栈是为了java虚拟机执行字节码所服务，而本地方法栈则是为了执行native方法所服务
	 * 4-当虚拟机调用本地（native）方法时，虚拟机不会创建新的栈帧，虚拟机栈会保持不变，虚拟机只是简单的动态连接并直接调用相关的本地方法
	 * <p>
	 * 本地方法就是c/c++ 程序 在线程执行的过程中如果需要调用jni方法的情况
	 * 比如网络通信 文件底层操作 甚至是String的intern的方法都是jni方法(intern用来返回常量池中的某字符串，如果常量池中已经存在该字符串，则直接返回常量池中该对象的引用。否则，在常量池中加入该对象，然后 返回引用)
	 * 本地方法栈的自由的相当高，靠不同的jvm厂商实现
	 */
	private void jniMethodStack() {
	}

	/**
	 * 堆内存
	 * <p>
	 * 1-堆内存是jvm中最大的内存区域
	 * 2-线程共享
	 * 3-jvm在运行期间几乎创建的所有对象都存放在此，所以此地也是gc重点照顾的地方，也称gc堆 。
	 * 4-堆内存 一般分为新生代和老生代。详细的分为eden区，from survivor区 和 to survivor区
	 * 5-当堆耗尽的时候，JVM会抛出java.lang.OutOfMemoryError 异常
	 * 6-堆的大小可以通过JVM选项-Xms和-Xmx来进行调整
	 * <p>
	 * Eden区 新对象或者生命周期很短的对象会存储在这个区域中，这个区的大小可以通过-XX:NewSize和-XX:MaxNewSize参数来调整。
	 * 新生代GC（垃圾回收器）会清理这一区域。
	 * Survivor区 那些历经了Eden区的垃圾回收仍能存活下来的依旧存在引用的对象会待在这个区域。
	 * 这个区的大小可以由JVM参数-XX:SurvivorRatio来进行调节。
	 * 老年代 那些在历经了Eden区和Survivor区的多次GC后仍然存活下来的对象（当然了，是拜那些挥之不去的引用所赐）会存储在这个区里。
	 * 这个区会由一个特殊的垃圾回收器来负责。年老代中的对象的回收是由老年代的GC（major GC）来进行的。
	 */
	private void heapMemory() {
	}

	/**
	 * 方法区
	 * <p>
	 * 1-线程共享
	 * 2- java7之前，方法区位于永久代(PermGen)，永久代和堆相互隔离，永久代的大小在启动JVM时可以设置一个固定值，不可变；
	 * 3- java8中，取消永久代，方法存放于元空间(Metaspace)，元空间仍然与堆不相连，但与堆共享物理内存，逻辑上可认为在堆中
	 * <p>
	 * 虽然在jvm规范中，将堆内存（方法区-作者笔误）划分为堆内存的一个逻辑分区，但是还是被经常称为“非堆”，有时候也称之为“持久代”。
	 * 主要是站在垃圾回收器的角度进行划分，但是这种叫法比较欠妥
	 * <p>
	 * 在hotSpot jvm中，方法区还会进一步细分为持久代和代码缓冲区
	 * -持久代 这个区域会存储包括类定义，结构，字段，方法（数据及代码）以及常量在内的类相关数据。
	 * 它可以通过-XX:PermSize及 -XX:MaxPermSize来进行调节。
	 * 如果它的空间用完了，会导致java.lang.OutOfMemoryError: PermGen space的异常
	 * -代码缓冲区主要存储 编译后的本地接口代码（和硬件相关）以及jit（just in time）编译器生成的代码，当然不同的jvm会有不同的实现
	 */
	private void methodArea() {
	}

}
